package com.example.utils;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.LinkedList;

import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.text.format.Time;

import com.example.canavar.MainActivity;
import com.example.canavar.R;
import com.example.canavar.SearchTask;
import com.example.canavar.SettingsFragment;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

public class SearchResultManager {

	ArrayList<SearchResultUpdateListener> mSearchResultUpdateListeners = new ArrayList<SearchResultUpdateListener>();

	private LinkedList<SearchResult> mResults;
	private LinkedList<LogEntry> mLogs;
	LogEntry aNewEntry = null;
	private static SearchResultManager mInstance = null;

	private SearchResultManager() {
		Utils.Log("singleton instance created");
	};

	public static SearchResultManager getInstance() {
		if (mInstance == null) {
			mInstance = new SearchResultManager();
		}
		return mInstance;
	}

	public void init(Context context) {
		Utils.Log("init called");
		SharedPreferences shared = PreferenceManager
				.getDefaultSharedPreferences(context);

		// Get logs
		String sJson = shared.getString(
				SettingsFragment.LOGS_PREF_KEY, "");
//		sJson = ""; //used to reset the pref
		Utils.Log("Logs in pref: " + sJson);
		mLogs = new LinkedList<LogEntry>();		
		if (!sJson.isEmpty()) {
			Gson gson = new Gson();
			Type LinkedListType = new TypeToken<LinkedList<LogEntry>>() {
			}.getType();

			for (LogEntry log : (LinkedList<LogEntry>) gson.fromJson(sJson,
					LinkedListType))
				mLogs.add(log);				
			removeOldLogs();
		}

		// Get results LinkedList
		sJson = shared.getString(
				SettingsFragment.RESULTS_PREF_KEY, "");
//		 sJson = ""; //used to reset the pref
		Utils.Log("Results in pref: " + sJson);
		mResults = new LinkedList<SearchResult>();
		if (!sJson.isEmpty()) {
			Gson gson = new Gson();
			Type LinkedListType = new TypeToken<LinkedList<SearchResult>>() {
			}.getType();

			for (SearchResult res : (LinkedList<SearchResult>) gson.fromJson(sJson,
					LinkedListType))
				mResults.add(res);	
			removeOldResults();
		}

		fireSearchResultsChanged(mResults);
	}


	private void removeOldResults() {
		int today = Utils.getDayFromTime(Utils.getNow());
		while (mResults.size() > 0 && mResults.peek().getDay() < today - 3)
			mResults.removeLast();
	}

	private void removeOldLogs() {
		int today = Utils.getDayFromTime(Utils.getNow());
		while (mLogs.size() > 0
				&& (Utils.getDayFromTime(mLogs.peek().Time) < today - 3 || mLogs.size() > 10))
			mLogs.removeFirst();
	}

	public void saveState(Context context) {
		Utils.Log("saveState called");
		SharedPreferences shared = PreferenceManager
				.getDefaultSharedPreferences(context);
		SharedPreferences.Editor editor = shared.edit();
		Utils.Log(" LinkedList : " + mResults.toString());
		editor.putString(SettingsFragment.RESULTS_PREF_KEY,
				new Gson().toJson(mResults));
		Utils.Log(" Logs : " + mLogs.toString());
		editor.putString(SettingsFragment.LOGS_PREF_KEY,
				new Gson().toJson(mLogs));
		editor.commit();
	}

	public LinkedList<SearchResult> getResults() {
		return mResults;
	}

	public void addResult(SearchResult result) {

		if (mResults.contains(result)) {
			Utils.Log(" Result already exists: " + result.toString());
		} else {
			mResults.add(result);

			Utils.Log(" Result added: " + result.toString());
			Utils.Log("LinkedList size: " + mResults.size());
			fireSearchResultsChanged(result);
		}
	}

	public void addLog(String log) {		
		
		if (log.equalsIgnoreCase(SearchTask.START)) {
			aNewEntry = new LogEntry(Utils.getNow());
		}		
		else if(log.equalsIgnoreCase(SearchTask.END) && aNewEntry != null)
		{
			mLogs.add(aNewEntry);
		}
		else
		{
			aNewEntry.Entries.add(log);
		}		
	}
	
	private void fireSearchResultsChanged(LinkedList<SearchResult> results) {
		for (SearchResult res : results) {
			fireSearchResultsChanged(res);
		}
	}

	private void fireSearchResultsChanged(SearchResult result) {
		// propagate event to all listeners
		for (SearchResultUpdateListener listener : mSearchResultUpdateListeners) {
			listener.onSearchResultsChanged(result);
		}

	}

	public void setSearchResultUpdateListener(
			SearchResultUpdateListener listener) {
		// Store the listener object
		Utils.Log("SearchResultUpdateListener added " + listener.toString());
		this.mSearchResultUpdateListeners.add(listener);
	}

	public void removeSearchResultUpdateListener(
			SearchResultUpdateListener listener) {
		// Store the listener object
		Utils.Log("SearchResultUpdateListener removed " + listener.toString());
		this.mSearchResultUpdateListeners.remove(listener);
	}

	public class LogEntry {
					
		private LogEntry() {
		}

		private LogEntry(Time time) {			
			Time = time;	
			Entries = new ArrayList<String>();
		}
		
		public String toString()
		{
			return this.Time.format("%H%M") + "      entries size: " + this.Entries.size();
		}
		
		public Time Time;
		public ArrayList<String> Entries;		
		
	}

	public LinkedList<LogEntry> getLogs() {		
		return mLogs;
	}
}
